import { CameraStateControlled, CameraStateUncontrolled } from './jsx/allLiveEditors'
import CameraState from './jsx/api/CameraState.js';

# Camera

Worldview's virtual camera is positioned with respect to a "target" object. The camera faces in the same direction as the target (yaw only, specified by `targetOrientation`),
and is positioned so that it "looks at" the `target`, or at the `targetOffset` (in the reference frame of the target) if specified.

Relative to the point it "looks at", the camera's position is controlled by `distance`, `phi`, and `thetaOffset`, in [spherical coordinates](https://en.wikipedia.org/wiki/Spherical_coordinate_system).
With `phi = 0` the camera points straight down from above the target, and with `phi = Math.PI` it points straight up from below. `thetaOffset` controls extra yaw (in addition to following the `targetOrientation`), and `distance` specifies the zoom level.

CameraStore holds the camera state and offers methods to handle camera rotation, zoom and move. It also provides `setCameraState` methods to allow you to reset the full/partial camera state. These methods are currently encapsulated inside Worldview.

You can move the camera around using the mouse/trackpad, or by using the keyboard: *a/s/d/f* (for `targetOffset`), *q/e* (for `thetaOffset`), *r/f* (for `phi`), and *z/x* (for `distance`).

## cameraState

| Name                | Type      | Default        | Description                                                                                     |
| ------------------- | --------- | -------------- | ----------------------------------------------------------------------------------------------- |
| `perspective`       | `boolean` | `true`         | type of the camera, default to perspective (3D), pass in `false` to use orthographic (2D)       |
| `target`            | `vec3`    | `[0, 0, 0]`    | position of the target                                                                          |
| `targetOrientation` | `quat`    | `[0, 0, 0, 1]` | orientation of the target (only yaw angle is used to determine camera placement)                |
| `targetOffset`      | `vec3`    | `[0, 0, 0]`    | additional offset for the camera, specified in the `target`/`targetOrientation` reference frame |
| `distance`          | `number`  | `75`           | distance between the camera and target                                                          |
| `phi`               | `number`  | `Math.PI/4`    | angle in radians from +z pole to -z pole, range: [0, π]. Ignored when `perspective` is false    |
| `thetaOffset`       | `number`  | `0`            | offset azimuth angle in radians, +θ corresponds to +x→+y, range: [0, 2π]                        |
| `fovy`              | `number`  | `Math.PI/4`    | field of view in the y direction, in radians                                                    |
| `near`              | `number`  | `0.01`         | distance to the frustum near plane                                                              |
| `far`               | `number`  | `5000`         | distance to the frustum far plane                                                               |

<CameraState />

## Controlled and uncontrolled cameraState

You must choose one of the two options for camera state:

**Controlled** using `cameraState` and `onCameraStateChange` as props:

<CameraStateControlled />

**Uncontrolled** using `defaultCameraState` as props. _Notice how the cameraState doesn't change when you change the distance in the input._ ([Understanding uncontrolled components](https://reactjs.org/docs/uncontrolled-components.html))

<CameraStateUncontrolled />

If none of the three props are passed in, Worldview is **Uncontrolled** using `DEFAULT_CAMERA_STATE`.

## cameraStateSelectors

We export a set of selectors to allow you to get additional information based on the cameraState:

```js
import { cameraStateSelectors } from "regl-worldview";

// Full cameraState is required
const targetHeading = cameraStateSelectors.targetHeading(cameraState);
const theta = cameraStateSelectors.theta(cameraState);
```

| Name            | Type     | Description                                                          |
| --------------- | -------- | -------------------------------------------------------------------- |
| `orientation`   | `quat`   | orientation of the camera                                            |
| `position`      | `vec3`   | position of the camera                                               |
| `targetHeading` | `quat`   | heading direction of the target                                      |
| `theta`         | `number` | azimuth angle in radians, +θ corresponds to +x→+y, range: [0, 2π]    |
| `view`          | `mat4`   | field of view, control the behavior of the projection transformation |
